Technical Q&AJava 20 - Using
|
import java.text.*; public class CurrentTimeChecker implements Runnable { Thread thread = new Thread(this); long[] times = new long[500]; long lastT = 0; int timesCursor = 0; public boolean timeToStop = false; NumberFormat nf = null; public CurrentTimeChecker() { initNF(); thread.start(); } void initNF() { nf = NumberFormat.getNumberInstance(); nf.setMinimumFractionDigits(0); nf.setMaximumFractionDigits(0); int numDigits = Long.toString(Long.MAX_VALUE).length(); nf.setMinimumIntegerDigits(numDigits); nf.setMaximumIntegerDigits(numDigits); } static public void main(String[] args) { new CurrentTimeChecker(); } public void run() { while(! timeToStop) { try { Thread.sleep(1000); } catch(InterruptedException e) {} long t = System.currentTimeMillis(); if ( t > lastT ) System.out.println(nf.format(t)); if ( t < lastT ) { System.out.println(nf.format(t) + " <---- "); java.awt.Toolkit.getDefaultToolkit().beep(); } times[timesCursor++] = t; if (timesCursor >= times.length) timesCursor = 0; lastT = t; } System.out.println("Finished..."); } } // class CurrentTimeChecker |
My code sleeps for a certain interval, then calculates the elapsed time. On my PowerBook, sometimes I get negative time intervals. Why does this happen?
A: This is the result of a bug in the MRJ. It is not the sleep( )
that is causing the problem, it is the call to System.currentTimeMillis( )
that is causing this behavior. This problem may occur for ANY interval calculation regardless of whether sleep( )
is called or not. As of this writing (November 29), the issue has been resolved and should now be available in the latest beta seed. Incidentally, the fix was discovered as a consequence of long file name testing on Mac OS 9.
Mac OS 9 has a millisecond accurate time service available that works with "modern" hardware. Older systems and older hardware have to make do with unreconciled fast timers and the 1-second granular clock. Previous MRJ versions would sample the 1-second granule clock, mark that sample as being .0, and count milliseconds forward from the timer clock. This algorithm would restart every minute. The effect is that every minute MRJ would report times being up to plus/minus one second from the previous time. There may even have been cases where reported time intervals would briefly go backwards.
The new behavior on Mac OS 9 and "modern" hardware (G3 for the most part) is to let Mac OS do it for us. Otherwise, we pause on startup and note and track (with the timer) the transition of the 1-second granule clock. This calibration is repeated after an interval of several minutes.
This new fix will be present in MRJ 2.2. Developers who are ADC members can access the new MRJ from the ADC seeding site.
For developers who don't have access to the seed, we recommend that you use Mac OS 9, which should minimize this problem on new hardware. If you need to do timing on previous operating systems or older machines, we recommend that you check out Greg Guerin's example on how to use the Macintosh microsecond timer, instead. Not only will you not experience this problem, but you will also be able to get finer grained control:
"If you're interested, the source for my test program has a class that will read the free-running microsecond timer under MRJ. Obviously, it won't work on other platforms, but you can write platform-sensing Java code to pick between implementations. As far as I can tell, this counter is completely free-running, and counts microseconds since last restart, though I don't know if it has PowerBook peculiarities in low-power modes. Also, it doesn't seem to be subject to the backwards-time drift correction currently observable in MRJ. While this won't help sleep(long) or wait(long), it should let you calculate elapsed times without worrying about drift-correcting adjustments botching the calculation."